package com.mars.component.mail;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import com.mars.component.utils.RegexUtils;


/**
 * 邮件帮助类<br>
 * 发送模板邮件，需要在类路径下的template目录下建立模板文件(src/main/resources/template)<br>
 * @author yhaoquan
 *
 */
public class MailUtils {
	
	private Logger logger = LoggerFactory.getLogger(MailUtils.class);
	
	@Autowired
	private FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean ;

	/**
	 * Spring 线程池异步执行器
	 */
	@Autowired
	private TaskExecutor taskExecutor;

	@Autowired
	private JavaMailSender mailSender;
	
	private String charset = "utf-8";

	private String mailSubject;

	private String mailPersonal;

	private String mailFrom;

	/**
	 * 异步发送邮件
	 */
	public void sendMailAsync(final String to, final String content, final File... files) {
		this.taskExecutor.execute(new Runnable() {
			@Override
			public void run() {
				sendMail(to, content, files);
			}
		});
	}

	public void sendMailAsync(final String to, final String tplName, final Map<String, Object> data, final File... files) {
		this.taskExecutor.execute(new Runnable() {
			@Override
			public void run() {
				sendMail(to, tplName, data, files);
			}
		});
	}

	public boolean sendMail(String to, String content, File... files) {
		return sendMail(this.mailPersonal, this.mailFrom, to, null, null, this.mailSubject, content, null, null, files);
	}

	public boolean sendMail(String to, String subject, String content, File... files) {
		return sendMail(this.mailPersonal, this.mailFrom, to, null, null, subject, content, null, null, files);
	}

	public boolean sendMail(String from, String to, String subject, String content, File... files) {
		return sendMail(this.mailPersonal, from, to, null, null, subject, content, null, null, files);
	}

	public boolean sendMail(String personal, String from, String to, String subject, String content, File... files) {
		return sendMail(personal, from, to, null, null, subject, content, null, null, files);
	}

	public boolean sendMail(String personal, String from, String to, String cc, String subject, String content, File... files) {
		return sendMail(personal, from, to, cc, null, subject, content, null, null, files);
	}

	public boolean sendMail(String personal, String from, String to, String cc, String bcc, String subject, String content, File... files) {
		return sendMail(personal, from, to, cc, bcc, subject, content, null, null, files);
	}

	public boolean sendMail(String to, String tplName, Map<String, Object> data, File... files) {
		return sendMail(this.mailPersonal, this.mailFrom, to, null, null, this.mailSubject, null, tplName, data, files);
	}

	public boolean sendMail(String to, String subject, String tplName, Map<String, Object> data, File... files) {
		return sendMail(this.mailPersonal, this.mailFrom, to, null, null, subject, null, tplName, data, files);
	}

	public boolean sendMail(String from, String to, String subject, String tplName, Map<String, Object> data, File... files) {
		return sendMail(null, from, to, null, null, subject, null, tplName, data, files);
	}

	public boolean sendMail(String personal, String from, String to, String subject, String tplName, Map<String, Object> data, File... files) {
		return sendMail(personal, from, to, null, null, subject, null, tplName, data, files);
	}

	public boolean sendMail(String personal, String from, String to, String cc, String subject, String tplName, Map<String, Object> data, File... files) {
		return sendMail(personal, from, to, cc, null, subject, null, tplName, data, files);
	}

	public boolean sendMail(String personal, String from, String to, String cc, String bcc, String subject, String tplName, Map<String, Object> data, File... files) {
		return sendMail(personal, from, to, cc, bcc, subject, null, tplName, data, files);
	}

	/**
	 * 发送邮件
	 * 
	 * @param personal
	 *            名称（邮件发送者名称）
	 * @param from
	 *            发送者（邮件地址）
	 * @param to
	 *            发送至（邮件地址）
	 * @param subject
	 *            主题（内容标题）
	 * @param cc
	 *            抄送至（邮件地址）
	 * @param bcc
	 *            暗送至（邮件地址）
	 * @param content
	 *            邮件正文
	 * @param tplName
	 *            模板名称（xxx.ftl ， 模板地址：/WEB-INF/views/mail/../mail.ftl）
	 * @param data
	 *            模板数据
	 * @return boolean 成功或失败
	 */
	public boolean sendMail(String personal, String from, String to, String cc, String bcc, String subject, String content, String tplName, Map<String, Object> data, File... files) {
		try {

			MimeMessage mimeMessage = mailSender.createMimeMessage();
			MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, getCharset());

			messageHelper.setFrom(from, personal);
			setTo(to, mimeMessage);
			setCc(cc, mimeMessage);
			setBcc(bcc, mimeMessage);
			messageHelper.setSubject(subject);
			messageHelper.setText(getHtmltext(content, tplName, data), true);

			setAttachment(files, null, null, messageHelper);

			mailSender.send(mimeMessage);

			logger.info("主题    ：" + subject);
			logger.info("发送人：" + from);
			logger.info("收件人：" + to);
			logger.info("抄送人：" + cc);
			logger.info("暗送人：" + bcc);
			for (File file : files) {
				logger.info("附件    ：" + file.getName());
			}
			logger.info("\r\n");

			return true;
		} catch (Exception e) {
			logger.error("发送邮件异常...", e);
		}
		return false;
	}

	/**
	 * 发送邮件消息队列
	 * @param mv
	 */
	public void sendMailQueue(MailVo mv) {
		//this.queueSender.sendObject(MQConst.MAIL_QUEUE, mv);
	}
	
	/**
	 * 发送邮件
	 * 主要用于消息队列发送
	 * @param mv
	 *            MailVo 邮件对象
	 * @return
	 */
	public boolean sendMail(MailVo mv) {
		try {

			MimeMessage mimeMessage = mailSender.createMimeMessage();
			MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, getCharset());

			messageHelper.setFrom((null == mv.getFrom() ? this.mailFrom : mv.getFrom()), (null == mv.getPersonal() ? this.mailPersonal : mv.getPersonal()));
			setTo(mv.getTo(), mimeMessage);
			setCc(mv.getCc(), mimeMessage);
			setBcc(mv.getBcc(), mimeMessage);
			messageHelper.setSubject((null == mv.getSubject() ? this.mailSubject : mv.getSubject()));
			messageHelper.setText(getHtmltext(mv.getContent(), mv.getTplName(), mv.getData()), true);

			setAttachment(mv.getAttachments(), mv.getAttachmentsArray(), mv.getAttachmentsString(), messageHelper);

			mailSender.send(mimeMessage);

			logger.info("主题    ：{}", (null == mv.getSubject() ? this.mailSubject : mv.getSubject()));
			logger.info("发送人：{}", (null == mv.getFrom() ? this.mailFrom : mv.getFrom()));
			logger.info("收件人：" + mv.getTo());
			logger.info("抄送人：" + mv.getCc());
			logger.info("暗送人：" + mv.getBcc());
			logger.info("附件    ：{}, {}, {}", mv.getAttachments(), mv.getAttachmentsArray(), mv.getAttachmentsString());
			logger.info("\r\n");

			return true;
		} catch (Exception e) {
			logger.error("发送邮件异常...", e);
		}
		return false;
	}

	/**
	 * 正文
	 * 
	 * @param content
	 * @param tplName
	 * @param data
	 * @return
	 */
	private String getHtmltext(String content, String tplName, Map<String, Object> data) {
		if (tplName != null && !tplName.trim().equals("")) {
			try {
				if(null != freeMarkerConfigurationFactoryBean) {
					content = FreeMarkerTemplateUtils.processTemplateIntoString(freeMarkerConfigurationFactoryBean.createConfiguration().getTemplate(tplName), data) ;
				}
			} catch (Exception e) {
				e.printStackTrace();
			} 
			return content ;
		} else {
			return content;
		}
	}

	/**
	 * 收件
	 * 
	 * @param to
	 * @param mimeMessage
	 * @throws MessagingException
	 */
	public void setTo(String to, MimeMessage mimeMessage) throws MessagingException {
		if (null != to && !"".equals(to.trim())) {
			// 获取所有抄送人地址
			List<InternetAddress> list = address(to, "收件");
			// 设置可以群发和单发抄送人
			InternetAddress[] addrArray = (InternetAddress[]) list.toArray(new InternetAddress[list.size()]);
			// 设置抄送人地址
			mimeMessage.setRecipients(RecipientType.TO, addrArray);
		}
	}

	/**
	 * 抄送
	 * 
	 * @param cc
	 * @param mimeMessage
	 * @throws MessagingException
	 */
	public void setCc(String cc, MimeMessage mimeMessage) throws MessagingException {
		if (null != cc && !"".equals(cc.trim())) {
			List<InternetAddress> list = address(cc, "抄送");
			InternetAddress[] addrArray = (InternetAddress[]) list.toArray(new InternetAddress[list.size()]);
			mimeMessage.setRecipients(RecipientType.CC, addrArray);
		}
	}

	/**
	 * 暗送
	 * 
	 * @param bcc
	 * @param mimeMessage
	 * @throws MessagingException
	 */
	public void setBcc(String bcc, MimeMessage mimeMessage) throws MessagingException {
		if (null != bcc && !"".equals(bcc.trim())) {
			List<InternetAddress> list = address(bcc, "暗送");
			InternetAddress[] addrArray = (InternetAddress[]) list.toArray(new InternetAddress[list.size()]);
			mimeMessage.setRecipients(RecipientType.BCC, addrArray);
		}
	}

	/**
	 * 附件，文件对象
	 * 
	 * @param messageHelper
	 * @param attachments
	 * @throws MessagingException
	 */
	public void setAttachment(File[] attachments, String[] attachmentArray, String attachmentString, MimeMessageHelper messageHelper) throws MessagingException {
		if (null != attachments) {
			for (File file : attachments) {
				messageHelper.addAttachment(file.getName(), file);
			}
		}

		if (null != attachmentArray) {
			for (String path : attachmentArray) {
				File file = new File(path);
				messageHelper.addAttachment(file.getName(), file);
			}
		}

		if (null != attachmentString) {
			String[] filePaths = attachmentString.split(";");
			for (String path : filePaths) {
				File file = new File(path);
				messageHelper.addAttachment(file.getName(), file);
			}
		}
	}

	/**
	 * 解析邮件地址
	 * 
	 * @param address
	 * @param typeName
	 * @return
	 */
	public static List<InternetAddress> address(String address, String typeName) {
		List<String> failerAddr = new ArrayList<String>();

		List<InternetAddress> list = new ArrayList<InternetAddress>();

		String[] addrSplit = address.split(",");

		for (int i = 0; i < addrSplit.length; i++) {
			try {
				if (!"".equals(addrSplit[i]) && RegexUtils.isEmail(addrSplit[i])) {
					list.add(new InternetAddress(addrSplit[i]));
				} else {
					failerAddr.add(addrSplit[i]);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return list;
	}

	public String getMailPersonal() {
		return mailPersonal;
	}

	public void setMailPersonal(String mailPersonal) {
		this.mailPersonal = mailPersonal;
	}

	public JavaMailSender getMailSender() {
		return mailSender;
	}

	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public void setMailSender(JavaMailSender mailSender) {
		this.mailSender = mailSender;
	}

	public String getMailSubject() {
		return mailSubject;
	}

	public void setMailSubject(String mailSubject) {
		this.mailSubject = mailSubject;
	}

	public String getMailFrom() {
		return mailFrom;
	}

	public void setMailFrom(String mailFrom) {
		this.mailFrom = mailFrom;
	}

	public TaskExecutor getTaskExecutor() {
		return taskExecutor;
	}

	public void setTaskExecutor(TaskExecutor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}

}
